 /*******************************************************************************
  * Copyright (c) 2000, 2005 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/

 package org.eclipse.ui.internal.keys;

 import org.eclipse.jface.action.IContributionItem;
 import org.eclipse.jface.action.IStatusLineManager;
 import org.eclipse.jface.bindings.keys.KeySequence;
 import org.eclipse.ui.IWorkbench;
 import org.eclipse.ui.IWorkbenchWindow;
 import org.eclipse.ui.internal.WorkbenchWindow;
 import org.eclipse.ui.internal.util.StatusLineContributionItem;

 /**
  * <p>
  * The mutable state of the key binding architecture. This is the only piece of
  * the key binding architecture that changes (internally). It keeps track of
  * what partial key strokes the user has entered. In the case of functional
  * groups of key bindings, it allows the user to keep part of the key sequence
  * even after a match has been made. Only after releasing all of the modifier
  * keys would the sequence reset itself.
  * </p>
  * <p>
  * In the current implementation, a partial reset results in only one key
  * stroke being left in the sequence. However, this may change in the future.
  * </p>
  *
  * @since 3.0
  */
 class KeyBindingState {

     /**
      * The workbench window associated with this state. The state can only
      * exist for one window. When the focus leaves this window then the mode
      * must automatically be reset.
      */
     private IWorkbenchWindow associatedWindow;

     /**
      * This is the current extent of the sequence entered by the user. In an
      * application with only single-stroke key bindings, this will also be
      * empty. However, in applications with multi-stroke key bindings, this is
      * the sequence entered by the user that partially matches another one of
      * the application's active key bindings.
      */
     private KeySequence currentSequence;

     /**
      * The workbench that should be notified of changes to the key binding
      * state. This is done by updating one of the contribution items on the
      * status line.
      */
     private final IWorkbench workbench;

     /**
      * Constructs a new instance of <code>KeyBindingState</code> with an
      * empty key sequence, set to reset fully.
      *
      * @param workbenchToNotify
      * The workbench that this state should keep advised of changes
      * to the key binding state; must not be <code>null</code>.
      */
     KeyBindingState(IWorkbench workbenchToNotify) {
         currentSequence = KeySequence.getInstance();
         workbench = workbenchToNotify;
         associatedWindow = workbench.getActiveWorkbenchWindow();
     }

     /**
      * An accessor for the workbench window associated with this state. This
      * should never be <code>null</code>, as the setting follows the last
      * workbench window to have focus.
      *
      * @return The workbench window to which the key binding architecture is
      * currently attached; should never be <code>null</code>.
      */
     IWorkbenchWindow getAssociatedWindow() {
         return associatedWindow;
     }

     /**
      * An accessor for the current key sequence waiting for completion.
      *
      * @return The current incomplete key sequence; never <code>null</code>,
      * but may be empty.
      */
     KeySequence getCurrentSequence() {
         return currentSequence;
     }

     /**
      * Gets the status line contribution item which the key binding
      * architecture uses to keep the user up-to-date as to the current state.
      *
      * @return The status line contribution item, if any; <code>null</code>,
      * if none.
      */
     StatusLineContributionItem getStatusLine() {
         if (associatedWindow instanceof WorkbenchWindow) {
             WorkbenchWindow window = (WorkbenchWindow) associatedWindow;
             IStatusLineManager statusLine = window.getStatusLineManager();
             // TODO implicit dependency on IDE's action builder
 // @issue implicit dependency on IDE's action builder
 if (statusLine != null) { // this can be null if we're exiting
 IContributionItem item = statusLine
                         .find("ModeContributionItem"); //$NON-NLS-1$
 if (item instanceof StatusLineContributionItem) {
                     return ((StatusLineContributionItem) item);
                 }
             }
         }

         return null;
     }

     /**
      * <p>
      * Resets the state based on the current properties. If the state is to
      * collapse fully or if there are no key strokes, then it sets the state to
      * have an empty key sequence. Otherwise, it leaves the first key stroke in
      * the sequence.
      * </p>
      * <p>
      * The workbench's status lines are updated, if appropriate.
      * </p>
      */
     void reset() {
         currentSequence = KeySequence.getInstance();
         updateStatusLines();
     }

     /**
      * A mutator for the workbench window to which this state is associated.
      *
      * @param window
      * The workbench window to associated; should never be <code>null</code>.
      */
     void setAssociatedWindow(IWorkbenchWindow window) {
         associatedWindow = window;
     }

     /**
      * A mutator for the partial sequence entered by the user.
      *
      * @param sequence
      * The current key sequence; should not be <code>null</code>,
      * but may be empty.
      */
     void setCurrentSequence(KeySequence sequence) {
         currentSequence = sequence;
         updateStatusLines();
     }

     /**
      * Updates the text of the status line of the associated shell with the
      * current sequence.
      */
     private void updateStatusLines() {
         StatusLineContributionItem statusLine = getStatusLine();
         if (statusLine != null) {
             statusLine.setText(getCurrentSequence().format());
         }
     }
 }

